package qpidClient;

import java.util.UUID;

import javax.jms.DeliveryMode;
import javax.jms.JMSException;
import javax.jms.TopicSubscriber;

import org.apache.qpid.AMQException;
import org.apache.qpid.client.AMQConnection;
import org.apache.qpid.client.AMQSession;
import org.apache.qpid.client.AMQTopic;
import org.apache.qpid.client.TopicPublisherAdapter;
import org.apache.qpid.client.message.AbstractJMSMessage;
import org.apache.qpid.client.message.JMSTextMessage;
import org.apache.qpid.url.URLSyntaxException;

/**
 * Generic Qpid client for the broker failure detection system.
 * The clients in the system connect to only ONE broker, so the only connection
 * and session they have can be an attribute of the class.
 * Furthermore, only Detector.java, Controller.java and SuperController.java
 * extend QpidClient, and they all connect to the broker controller.
 * I'll let the broker to connect to as a parameter to remember to which broker
 * a connection is being set, but I'll hardcode the port (always 5672).
 */
public class QpidClient {
	
	//unique id of the client
    protected final String CLIENT_ID;

	//username
    protected final String USERNAME = "guest"; //TODO: not always the same
    //password
    protected final String PASSWORD = "guest"; //TODO: not always the same
	
    //name of the virtual host
    protected final String VIRTUAL_HOST = "news";
    //an exchange that already exists is used
    protected final String EXCHANGE = "amq.topic";

    //connection to the broker to publish messages to
    protected AMQConnection connection;
    //session in connection
    protected AMQSession session;
    
    //getters
    public String getCLIENT_ID() {
		return CLIENT_ID;
	}
    public String getUSERNAME() {
    	return USERNAME;
    }
    public String getPASSWORD() {
    	return PASSWORD;
    }
    public String getVIRTUAL_HOST() {
    	return VIRTUAL_HOST;
    }
    public String getEXCHANGE() {
    	return EXCHANGE;
    }
    
    /**
     * Constructor.
     */
    public QpidClient() {
    	//get a unique ID
 	   	CLIENT_ID = UUID.randomUUID().toString();
    }
    
    /**
     * Create and start a connection and create a session in it.
     * 
     * @param brokerIP  IP address of the broker we want to connnect to
     * @throws AMQException  if there are problems
     * @throws URLSyntaxException  if there are problems
     * @throws JMSException  if there are problems
     */
    protected void openConnAndSess(String brokerIP)
    		throws URLSyntaxException, AMQException, JMSException {

        //create a connection
		connection = new AMQConnection(brokerIP, USERNAME, PASSWORD,
							  		   CLIENT_ID, VIRTUAL_HOST);
		//start the connection
		connection.start();
		
		//create a session, non transacted and auto acknowledged
 		session = (AMQSession)
 				connection.createSession(false, AMQSession.AUTO_ACKNOWLEDGE);
 		
    }
    
    /**
     * Creates a publisher to the given topic.
     * 
     * @param topicName  the topic to create a publisher to
     * @return  a publisher to the given topic
     * @throws JMSException  if there are problems
     */
    protected TopicPublisherAdapter getPublisherForTopic(String topicName)
    		throws JMSException {
    	//create topicURL
		String tURL = "topic://" + EXCHANGE + "/?routingkey='" + topicName
					  + "'&exclusive='true'&autodelete='true'";
		//create topic
		AMQTopic topic = (AMQTopic) session.createTopic(tURL);

		//return publisher
		return (TopicPublisherAdapter) session.createPublisher(topic);
    }
    
    /**
     * Creates a subscriber to the given topic.
     * 
     * @param topicName  topic to create the subscriber to
     * @return  a subscriber to the given topic
     * @throws JMSException  if there are problems
     */
    protected TopicSubscriber getSubscriberForTopic(String topicName)
    		throws JMSException {
    	//create topicURL
		String tURL = "topic://" + EXCHANGE + "/?routingkey='" + topicName
					  + "'&exclusive='true'&autodelete='true'";
		//create topic
		AMQTopic topic = (AMQTopic) session.createTopic(tURL);
		
		//get a random subscription id
		String subscriptionId = UUID.randomUUID().toString();
		//return a subscriber
		return session.createDurableSubscriber(topic, subscriptionId);
    }
    
    /**
     * Creates a text message with the given text and makes the given publisher
     * send it.
     * 
     * @param publisher  the publisher who will send the message
     * @param text  text of the message
     * @throws JMSException  if there are problems
     */
    protected void sendMessage(TopicPublisherAdapter publisher, String text)
    		throws JMSException {
    	//create the message to send
		JMSTextMessage txtMessage =
				(JMSTextMessage) session.createTextMessage(text);
		//send the message
		publisher.publish(txtMessage, DeliveryMode.PERSISTENT,
						  AbstractJMSMessage.DEFAULT_PRIORITY,
						  AbstractJMSMessage.DEFAULT_TIME_TO_LIVE);
    }
    
    /**
     * Close the connection.
     * 
     * @throws JMSException  if there are problems
     */
    protected void closeConnection() throws JMSException {
        connection.close();
    }

}
